#include <iostream>
#include <map>
#include <fstream>
#include <exception>
#include <GL/glew.h>
#include "Quaternion.h"
#include "IniParser.h"
#include "RenderTarget.h"

using namespace std;

enum { DEBUG = false };

extern GLuint gWVPLocation;

/**************************************************************/
/**************************************************************/
RenderTarget::RenderTarget(void)
:  mMesh(NULL), mTexture(NULL) 
{
	mMatrix = Matrix4::IDENTITY;
}

RenderTarget::~RenderTarget() {
}

void RenderTarget::setPosition(float p_x, float p_y, float p_z) {
	mMatrix.setTrans(Vector3f(p_x, p_y, p_z));
}

void RenderTarget::rotateTarget(float r_x, float r_y, float r_z) {
	Quaternion qx(Radian(Degree(r_x)), Vector3f::UNIT_X);
	Quaternion qy(Radian(Degree(r_y)), Vector3f::UNIT_Y);
	Quaternion qz(Radian(Degree(r_z)), Vector3f::UNIT_Z);
	Quaternion q = qx * qy * qz;

	Matrix3 rot;
	q.ToRotationMatrix(rot);
	mMatrix = mMatrix.concatenate(Matrix4(rot));
}

void RenderTarget::rotateTarget(const Vector3f& v) {
	assert(false);
}

void RenderTarget::transTarget(float t_x, float t_y, float t_z) {
	mMatrix[0][3] += t_x;
	mMatrix[1][3] += t_y;
	mMatrix[2][3] += t_z;
}

void RenderTarget::transTarget(const Vector3f& v) {
	assert(false);
}

void RenderTarget::scaleTarget(float s_x, float s_y, float s_z) {
	mMatrix.setScale(Vector3f(s_x, s_y, s_z));
}

void RenderTarget::scaleTarget(const Vector3f& v) {
	mMatrix.setScale(v);
}

void RenderTarget::makeTransform(const Vector3f& position, const Vector3f& scale, const Quaternion& orientation) {
	mMatrix.makeTransform(position, scale, orientation);
}

void RenderTarget::draw(void) {
	if (mMesh != NULL) {
		mMesh->Render();
	}
}

/**************************************************************/
/**************************************************************/
template<> TargetManager* Singleton<TargetManager>::m_singleton = 0;

TargetManager& TargetManager::getSingleton(void) {
	return *m_singleton;
}

TargetManager* TargetManager::getSingletonPtr(void) {
	return m_singleton;
}

TargetManager::TargetManager(): mTargetVec(0) {
}

void TargetManager::importMesh(const char* model_path, const char* tex_path) {
	RenderTarget* pTarget = new RenderTarget();
	pTarget->mMesh = new Mesh();
    if (!pTarget->mMesh->LoadMesh(model_path)) {
        delete pTarget;
        return;
    }

	assert(pTarget);

	//计算模型的顶点法线
	//pTarget->mMesh->calcNormals();
	//计算模型的包围
	//pTarget->createBSphere();

	mTargetVec.push_back(pTarget);
}

/*
static void setShaders() {
	GLint result;

	//创建对像并添加shader
	g_program = glCreateProgram();
	shaderAttachFromFile(g_program, GL_VERTEX_SHADER, "shader.vert");
	shaderAttachFromFile(g_program, GL_FRAGMENT_SHADER, "shader.frag");

	glLinkProgram(g_program);
	glGetProgramiv(g_program, GL_LINK_STATUS, &result);
	if (result == GL_FALSE) {
		GLint length;
		glGetShaderiv(g_program, GL_INFO_LOG_LENGTH, &length);
		std::string log(length, ' ');
		glGetShaderInfoLog(g_program, length, &length, &log[0]);
		std::cerr << "shader链接失败,原因：" << log << endl;
		return;
	}
	//得到uniform 位置
	//g_programCameraPositionLocation = glGetUniformLocation(g_program, "cameraPosition");
	//g_programLightPositionLocation = glGetUniformLocation(g_program, "lightPosition");
	//g_programLightColorLocation = glGetUniformLocation(g_program, "lightColor");

}
*/

void TargetManager::importMeshFromIni(const char* ini_filename, const char* obj_name) {
	IniParser ini(ini_filename);

	char    *obj_path, *tex_path;
	char    tmpStr[128];

	sprintf(tmpStr, "%s:filename", obj_name);
	obj_path= ini.getstring(tmpStr, NULL);
	std::cout << "obj_path:" << obj_path<< endl;
	if (obj_path== NULL) {
		return;
	}

	int objsNum = getTargetsCount();

	importMesh(obj_path, tex_path);

	for (size_t i = objsNum; i < getTargetsCount(); ++i) {
		RenderTarget* pTarget = getTarget(i);

		sprintf(tmpStr, "%s:use_euler_or_matrix", obj_name);
		if (ini.getboolean(tmpStr, true) == false) {
			//使用欧拉表示法表示位置和旋转
			float px, py, pz, rx, ry, rz, sx, sy, sz;
			sprintf(tmpStr, "%s:position_x", obj_name);
			px = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:position_y", obj_name);
			py = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:position_z", obj_name);
			pz = ini.getdouble(tmpStr, 0);
			pTarget->setPosition(px, py,pz);
			//printf("%f %f %f\n", px, py, pz);

			sprintf(tmpStr, "%s:rotation_x", obj_name);
			rx = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:rotation_y", obj_name);
			ry = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:rotation_z", obj_name);
			rz = ini.getdouble(tmpStr, 0);
			pTarget->rotateTarget(rx, ry, rz);
			//printf("%f %f %f\n @Line: %d", rx, ry, rz, __LINE__);
            
			sprintf(tmpStr, "%s:scale_x", obj_name);
			sx = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:scale_y", obj_name);
			sy = ini.getdouble(tmpStr, 0);
			sprintf(tmpStr, "%s:scale_z", obj_name);
			sz = ini.getdouble(tmpStr, 0);
			pTarget->scaleTarget(sx, sy, sz);
			//printf("%f %f %f\n @Line: %d", sx, sy, sz, __LINE__);
		} else { //使用矩阵法
			assert(false);	//暂未实现
		}
		sprintf(tmpStr, "%s:mass", obj_name);
	}
}

RenderTarget* TargetManager::getTarget(size_t index) {
    return mTargetVec[index];
}

size_t TargetManager::getTargetsCount(void) const {
	return mTargetVec.size();
}
